package org.luxor.commons.workflow.listener;

import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.HistoryService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.event.ActivitiEntityEvent;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.task.IdentityLink;
import org.apache.commons.lang.StringUtils;
import org.luxor.commons.core.utils.SpringContextUtils;
import org.luxor.commons.workflow.component.cache.DeploymentContext;
import org.luxor.commons.workflow.constant.ExtensionVariableConst;
import org.luxor.commons.workflow.constant.TransientVariableConst;
import org.luxor.commons.workflow.utils.ProcessUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 创建任务(创建任务后调用)
 *
 * @author Mr.Yan  @date: 2021/10/27
 */
public class TaskCreatedListener implements ActivitiEventHandler {

    private static final Logger log = LoggerFactory.getLogger(TaskCreatedListener.class);

    @Override
    public void handle(ActivitiEvent event) {
        if (event != null && org.springframework.util.StringUtils.hasText(event.getProcessInstanceId())) {
            DeploymentContext.setProcInstId(event.getProcessInstanceId());
        }

        ActivitiEntityEvent entityEvent = (ActivitiEntityEvent) event;
        TaskEntity taskEntity = (TaskEntity) entityEvent.getEntity();

        TaskService taskService = SpringContextUtils.getBean(TaskService.class);

        // 设置任务受理人
        Object assignee = taskEntity.getTransientVariable(TransientVariableConst.ASSIGNEE);
        if (assignee != null && StringUtils.isNotBlank(assignee.toString())) {
            taskService.setAssignee(taskEntity.getId(), assignee.toString());
        }

        // 设置任务候选人
        List<String> candidateUserList = (List<String>) taskEntity.getTransientVariables().getOrDefault(TransientVariableConst.CANDIDATE_USER_LIST, new ArrayList<>());
        for (String candidateUser : candidateUserList) {
            taskService.addCandidateUser(taskEntity.getId(), candidateUser);
        }

        // 设置任务候选组
        List<String> candidateGroupList = (List<String>) taskEntity.getTransientVariables().getOrDefault(TransientVariableConst.CANDIDATE_GROUP_LIST, new ArrayList<String>());
        for (String candidateGroup : candidateGroupList) {
            taskService.addCandidateGroup(taskEntity.getId(), candidateGroup);
        }

        // 设置到期时间
        Object dueDate = taskEntity.getTransientVariables().get(TransientVariableConst.DUE_DATE);
        if (dueDate != null && (dueDate instanceof Date)) {
            taskService.setDueDate(taskEntity.getId(), (Date) dueDate);
        }

        // 设置优先级
        Object priority = taskEntity.getTransientVariables().get(TransientVariableConst.PRIORITY);
        if (priority != null && (priority instanceof Integer)) {
            taskService.setPriority(taskEntity.getId(), (Integer) priority);
        }

        Object[] userIds = taskEntity.getCandidates().stream().map(IdentityLink::getUserId).filter(StringUtils::isNotBlank).sorted().toArray();
        Object[] groupIds = taskEntity.getCandidates().stream().map(IdentityLink::getGroupId).filter(StringUtils::isNotBlank).sorted().toArray();
        String candidate = "userId:" + Arrays.toString(userIds) + ",groupId:" + Arrays.toString(groupIds);
        log.debug("任务创建(TaskCreatedListener). TaskId: " + taskEntity.getId() + "(" + taskEntity.getName()
                + "),ProcInstId: " + entityEvent.getProcessInstanceId()
                + ",ExecutionId: " + taskEntity.getExecutionId()
                + ",Candidate: " + candidate
                + ",Assignee: " + taskEntity.getAssignee());

        // 所有节点跳过？
        Object allSkip = taskEntity.getVariable(ExtensionVariableConst.ALL_SKIP);
        if (allSkip != null && Boolean.parseBoolean(allSkip.toString())) {
            taskService.addComment(taskEntity.getId(), taskEntity.getProcessInstanceId(), "自动跳过(ALL_SKIP)");
            taskService.complete(taskEntity.getId());
            return;
        }

        if (StringUtils.isEmpty(taskEntity.getAssignee()) && CollectionUtils.isEmpty(taskEntity.getCandidates())) {
            // 任务节点执行人为空时跳过?
            Object userEmptySkip = taskEntity.getVariable(ExtensionVariableConst.USER_EMPTY_SKIP);
            if (userEmptySkip != null && Boolean.valueOf(userEmptySkip.toString())) {
                taskService.addComment(taskEntity.getId(), taskEntity.getProcessInstanceId(), "自动跳过(USER_EMPTY_SKIP)");
                taskService.complete(taskEntity.getId());
                return;
            }
            // 节点处理人为空时,打印警告日志
            warnUserEmpty(taskEntity);
        }
    }

    private void warnUserEmpty(TaskEntity taskEntity) {
        // 第一个用户任务?
        boolean isFirstUserTask = false;
        List<UserTask> firstUserTasks = ProcessUtils.findFirstUserTask(taskEntity.getProcessDefinitionId());
        for (UserTask firstUserTask : firstUserTasks) {
            if (firstUserTask.getId().equals(taskEntity.getTaskDefinitionKey())) {
                isFirstUserTask = true;
                break;
            }
        }
        if (!isFirstUserTask) {
            log.warn("\t\t 未指定任务办理人!!! 请'撤回任务'或'联系管理员进行人工干预'.  TaskDefKey: "
                    + taskEntity.getTaskDefinitionKey() + "(" + taskEntity.getName() + "),  TaskId: " + taskEntity.getId()
                    + ",ProcInstId: " + taskEntity.getProcessInstanceId()
                    + ",ExecutionId: " + taskEntity.getExecutionId());

            TaskService taskService = SpringContextUtils.getBean(TaskService.class);
            taskService.addComment(taskEntity.getId(), taskEntity.getProcessInstanceId(), "未指定任务办理人!!! 请'撤回任务'或'联系管理员进行人工干预'.");
            taskEntity.setAssignee("act_manager");
        }
    }

    /**
     * 获取历史任务实例
     *
     * @param processInstanceId 流程实例ID
     * @param taskDefKey        活动节点KEY
     */
    private HistoricTaskInstance getHistoricTaskInstance(String processInstanceId, String taskDefKey) {
        HistoryService historyService = SpringContextUtils.getBean(HistoryService.class);
        return historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .taskDefinitionKey(taskDefKey)
                .orderByHistoricTaskInstanceEndTime().desc()
                .singleResult();
    }
}
